# -*- coding: cp936 -*-
import md5
import sys
import time
import urllib
import urllib2
import httplib
import urlparse
import mimetypes
import os
from sgmllib import SGMLParser
import re

PROXY = {'http': 'http://proxy.sha.sap.corp:8080'}
USE_PROXY = True

def __install_proxy():
    proxy_handler = urllib2.ProxyHandler(PROXY)
    opener = urllib2.build_opener(proxy_handler)
    urllib2.install_opener(opener)

if USE_PROXY:
    __install_proxy()
    
# try to use simplejson first, otherwise fallback to XML
try:
    import simplejson
    RESPONSE_FORMAT = 'json'
except ImportError:
    try:
        from django.utils import simplejson
        RESPONSE_FORMAT = 'json'
    except ImportError:
        from xml.dom import minidom
        RESPONSE_FORMAT = 'xml'

# support Google App Engine.

try:
    from google.appengine.api import urlfetch

    def urlread(url, data=None):
        if data is not None:
            headers = {'Content-type': "application/x-www-form-urlencoded"}
            method = urlfetch.POST
        else:
            headers = {}
            method = urlfetch.GET

        result = urlfetch.fetch(url, method=method,
                                payload=data, headers = headers)

        if result.status_code == 200:
            return result.content
        else:
            raise urllib2.URLError("fetch error url=%s, code=%d" % (url, result.status_code))
        
except ImportError:
    def urlread(url, data=None):
        response = urllib2.urlopen(url, data=data)
        return response.read()


__all__ = ['API']
VERSION = '0.1'
APP_KEY = '13404'
CERT_CODE = '392acf0069ca11dd9f689e34e7a73ca8'

TAOBAO_URL = 'http://sip.alisoft.com/sip/rest/'
API_LIST_URL = 'http://isp.alisoft.com/apidoc/api/isp_%s/ispCategory_isp_%s.html'
NAMESPACES = []
URL_RE = re.compile('http://[^+]*?html')
DEBUG = True

API_LIST = {
    'taobao': {
        'items': {
            'instock': {
                'get': [
                    {'apiType': 1},
                    ('fields', list, [('default', ['iid'])]),
                    ('q', str, ['optional']),
                    ('page_no', int, ['optional']),
                    ('page_size', int, ['optional']),
                    ],
                },
##            'get': [
##                {'apiType': 1},
##                ('fields', list, [('default', ['iid'])]),
##                ('q', str, ['optional']),
##                ('nicks', list, ['optional']),
##                ('cid', str, ['optional']),
##                ('start_price', int, ['optional']),
##                ('end_price', int, ['optional']),
##                ('page_no', int, ['optional']),
##                ('page_size', int, ['optional']),
##                ('order_by', str, ['optional']), 
##                ]
            },


        'postages': {
            },

        'user': {
            },

        
        'users': {
            'get': [
                    {'apiType': 1},
                    ('nicks', list, []),
                    ('fields', list, [('default', ['nick', 'sex', 'buyer_credit', 'seller_credit'])])
                    ],
                },
            },
    
    'alisoft': {
        'validateUser': [
            {'apiType': 1},
            ('userId', str, []),
            ('appId', str, []),
            ('appInstanceId', str, []),
            ('token', str, []),
            ],
        },
    }


def __generate_api_list():
    path = os.path.join(os.path.dirname(__file__), 'api.list')
    if not os.path.exists(path):
        import sip_parser
        sip_parser.create_api_list()
    try:
        f = open(path, 'r')
        c = f.read()
        API_LIST = None
        API_LIST = simplejson.loads(c)
    finally:
        f.close()


class Namespace(object):
    def __init__(self, name, client=None):
        self._name = name
        self._client = client
        self._parent = None
        self._children = []
        self._proxy = None

    def fullName(self):
        if self._parent is None:
            return self._name
        else:
            return '%s.%s' % (self._parent.fullName(), self._name)

    def title(self):
        if self._parent is None:
            return self._name.title()
        else:
            return '%s%s' % (self._parent.title(), self._name.title())
        
    def addChild(self, child):
        child._parent = self
        self._children.append(child)
        self.__dict__[child._name] = child

    def createProxy(self, client):
        if self._proxy is None:
            return Namespace(self._name)
        else:
            return eval('%s(self._name, client)' % (self._proxy.__name__))
            
    def __str__(self):
        return self.fullName()

    def __repr__(self):
        return '%s' % (self.fullName())
        
    def __call__(self, method=None, args=None):
        if method is None:
            return self
        
        return self._client('%s.%s' % (self.fullName(), method), args)

   
def __generate_namespace(namespace, parent=None):
    current = Namespace(namespace[0])
    if parent is not None:
        parent.addChild(current)
        
    methods = {}

    for child in namespace[1].items():
        if type(child[1]) == dict:
            #generate sub-namespaces
            __generate_namespace(child, current)
        elif type(child[1]) == list:
            #genrate namespace proxy
            params = ['self']
            body = ['args = {}']

            #print child[0], child[1]
            for parameter in child[1]:
                if isinstance(parameter, tuple):
                    param_name = parameter[0]
                    param_type = parameter[1]
                    param_options = parameter[2]

                    method = child[0]
                    param = param_name
                    
                    for option in param_options:
                        if isinstance(option, tuple) and option[0] == 'default':
                            if param_type == list:
                                param = '%s=None' % param_name
                                body.append('if %s is None: %s = %s' % (param_name, param_name, repr(option[1])))
                            else:
                                param = '%s=%s' % (param_name, repr(option[1]))

                    if 'optional' in param_options:
                        param = '%s=None' % param_name
                        body.append('if %s is not None: args[\'%s\'] = %s' % (param_name, param_name, param_name))
                    else:
                        body.append('args[\'%s\'] = %s' % (param_name, param_name))

                    params.append(param)

            body.insert(0, '"""method"""')
            body.insert(0, 'def %s(%s):' % (method, ', '.join(params)))
            body.append('return self(\'%s\', args)' % method)

            exec('\n    '.join(body))
            methods[method] = eval(method)

    if len(methods) > 0:
        proxy = type('%sProxy' % (current.title()), (Namespace, ), methods)
        current._proxy = proxy
        globals()[proxy.__name__] = proxy
    
    return current

def __generate_namespaces():
    for namespace in API_LIST.items():
        current = __generate_namespace(namespace)
        NAMESPACES.append(current)

__generate_api_list()
__generate_namespaces()

class API(object):
    def __init__(self, app_key, cert_code, taobao_url=None):
        self._app_key = app_key
        self._cert_code = cert_code

        if taobao_url is None:
            self._taobao_url = TAOBAO_URL
        else:
            self._taobao_url = taobao_url

        self._create_proxies()

    
    def _create_proxy(self, namespace, parent=None):
        
        proxy = namespace.createProxy(self)
        if parent is None:
            self.__dict__[namespace._name] = proxy
        else:
            parent.addChild(proxy)
        
        for child in namespace._children:
            self._create_proxy(child, proxy)
            
    def _create_proxies(self):
        for namespace in NAMESPACES:
            self._create_proxy(namespace)
            
    def _add_session_args(self, args=None):
        """Adds session_id to args"""
        if args is None:
            args = {}
            
    def _build_post_args(self, method, args=None):
        """adds to args parameters that are necessary for every call to the API."""
        if args is None:
            args = {}

        for arg in args.items():
            if type(arg[1]) == list:
                args[arg[0]] = ','.join(str(a) for a in arg[1])
            elif type(arg[1]) == unicode:
                args[arg[0]] = arg[1].encode("UTF-8")

        #add common args
        args['sip_appkey'] = self._app_key
        args['sip_apiname'] = method
        args['v'] = '1.0'
        args['format'] = RESPONSE_FORMAT
        args['sip_timestamp'] = self._get_timestamp()
        args['sip_sign'] = self._sign(args)
        
        return args

    def _parse_response(self, response, method, format=None):
        if not format:
            format = RESPONSE_FORMAT

        if format == 'json':
            print response
            result = simplejson.loads(response)
        elif format == 'xml':
            print response
            dom = minidom.parseString(response)
            result = self._parse_response_item(dom)
            dom.unlink()

            #if 'error_rsp' in result: pass

    def _parse_response_item(self, node):
        if node.nodeType == node.DOCUMENT_NODE and \
            node.childNodes[0].hasAttributes(): pass
        
    def _get_timestamp(self):
        stime = None
        if(time.timezone == 0):
            gmtimefix = 28800
            stime = time.gmtime(gmtimefix + time.time())
        else:
            stime = time.localtime()
        strtime = time.strftime('%Y-%m-%d %X', stime)
        return strtime
    
    def _sign(self, args):
        src = self._cert_code + ''.join(["%s%s" % (k, v) for k, v in sorted(args.items())])
        return md5.new(src).hexdigest().upper()
##        encrypt = md5.new()
##        encrypt.update(self._cert_code)
##        for k,v in sorted(args.items()):
##            encrypt.update(k)
##            encrypt.update(v)
##
##        return encrypt.hexdigest().upper()
        
    def _unicode_urlencode(self, params):
        if isinstance(params, dict):
            params = params.items()
        return urllib.urlencode([(k, isinstance(v, unicode) and v.encode('UTF-8') or v)
                          for k, v in params])
    
    def __call__(self, method=None, args=None):
        post_data = self._unicode_urlencode(self._build_post_args(method, args))

        response = urlread(self._taobao_url, post_data)

        return self._parse_response(response, method)
        
if __name__ == '__main__':
    app_key = APP_KEY
    cert_code = CERT_CODE
    api = API(app_key, cert_code)
    
    api.taobao.items.get(fields=','.join(['iid', 'title', 'nick']), q='nike', v='1.0')
    #api.taobao.items.instock.get(fields=['iid', 'title', 'nick'], q='nike')
    #api.taobao.itemcats.get

